/* eslint-disable react/no-danger */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useRef } from 'react';
import { Collapse } from 'antd';
import hljs from 'highlight.js';
import MarkdownIt from 'markdown-it';
import renderStack from '@/assets/images/advanceReact/render_stack.png';
import renderInit from '@/assets/images/advanceReact/render_init.png';
import renderInitMain from '@/assets/images/advanceReact/render_init_main.png';
import renderRender from '@/assets/images/advanceReact/render_render.png';
import renderStructure from '@/assets/images/advanceReact/render_structure.png';
import renderApp from '@/assets/images/advanceReact/render_app.png';
import fiberTree from '@/assets/images/advanceReact/fiber_tree.png';

import 'highlight.js/styles/atom-one-light.css';
import './index.less';

const { Panel } = Collapse;
const mdParser = MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (error) {
        console.log(error);
      }
    }
    return ''; // 使用额外的默认转义
  },
});

export default function Render() {
  return (
    <div className="advance-react-wrapper">
      <img
        src={renderStack}
        alt=""
        width="50%"
        style={{ display: 'block', margin: '0 auto 20px' }}
      />
      <Collapse>
        <Panel header="1、render调用栈 -- 初始化阶段" key="1">
          <div>
            <img src={renderInit} alt="" width="50%" />
            <span>作用：完成fiber树中基本实体的创建</span>
          </div>
          <div>
            <img src={renderInitMain} alt="" width="50%" />
            <span>
              _internalRoot是一个FiberRootNode，他有一个current属性，该属性是个FiberNode，FiberNode正是Fiber结点对应的对象类型
            </span>
          </div>
          <ol>
            <li>请求当前Fiber节点的lane (优先级) </li>
            <li>结合lane (优先级),创建当前Fiber节点的update对象，并将其入队 </li>
            <li>调度当前节点(rootFiber)</li>
          </ol>
          ReactDom.render的首次渲染既然是同步的
          <p>React的启动方式</p>
          <ol>
            <li>legacy模式：ReactDOM.render(&lt;App&gt;,rootNode)，目前常用的就是该模式</li>
            <li>blocking模式：ReactDOM.createBlockingRoot(rootNode).render(&lt;App&gt;)</li>
            <li>concurrent模式：ReactDOM.createRoot(rootNode).render(&lt;App&gt;)，目标模式</li>
          </ol>
        </Panel>
        <Panel header="2、render调用栈 -- render阶段" key="2" className="renderParse">
          <p>
            React 15下的调和过程是一个递归的过程 在ReactDOM.render触发的同步模式下
            它仍然是一个深度优先搜索的过程 在这个过程中，beginWork 将创建新的Fiber节点
            而completeWork则负责将Fiber节点映射为DOM节点
          </p>
          <img src={renderRender} alt="" width="70%" />
          <p>
            <code>prepareFreshStack:</code>准备一个新的栈。
          </p>
          <p>
            <code>createWorkInProgress:</code>
            调用<code>createFiber</code>，workInProgress是createFiber方法的返回值(FiberNode)。
            <br />
            workInProgress的alternate指向current，current的alternate反过来指向workInProgress。
            <br />
            workInProgress节点其实就是current结点（即rootFiber）的副本。
          </p>
          <img src={renderStructure} alt="" width="50%" />
          <p>
            之后执行workLoopSync函数
            <br />
            <code>workLoopSync：</code>
            while循环反复判断workInProgress是否为空，循环调用<code>performUnitOfWork</code>
            ，从而触发对<code>beginWork</code>的调用，进而实现对新Fiber节点的创建。
          </p>
          <p>
            <code>beginWork:</code>
            beginWork的入参是一对用alternate连接起来的workInProgress和current节点。
            <br />
            beginWork的核心逻辑是根据fiber节点(workInProgress) 的tag属性的不同
            调用不同的节点创建函数。
            <br />
            根据tag值，调用update+类型名，从而调用<code>reconcileChildren</code>
            方法，生成当前节点的字节点
          </p>
          <p>
            <code>reconcileChildren:</code>主要调用
            <code>mountChildFibers、reconcileChildFibers</code>，而这两个函数本质又是
            <code>ChildReconciler(flag)</code>中flag为false和true时的返回值
          </p>
          <p>
            <code>ChildReconciler:</code>
            reconcileChildFibers和mountChildFibers的不同，在于对副作用的处理不同。具体在于返回的fiber节点有没有flags（effectTag）属性，如当flags
            =
            Placement，代表需要新增DOM节点。其他effectTag代表数据获取、订阅或者修改DOM等动作的副作用类型。
            <br />
            ChildReconciler中定义了大量如placeXXX、deleteXXX、 updateXXX、
            reconcileXXX等这样的函数，这些函数覆盖了对Fiber节点的创建、增加、删除、修改等动作,将直接或间接地
            被reconcileChildFibers所调用。
            <br />
            ChildReconciler的返回值是一个名为reconcileChildFibers的函数，这个函数是一个逻辑分发器，它将根据入参的不同，执行不同的Fiber节点操作,最终返回不同的目标Fiber节点
          </p>
          <div style={{ display: 'flex', gap: 60 }}>
            <img src={renderApp} alt="" width="40%" />
            <img src={fiberTree} alt="" width="50%" />
          </div>
          <p>
            render阶段的目标：找出界面中需要处理的更新，并不是所有的节点都要更新，如在挂载阶段，对图中的整棵workInProgress递归完毕后，React
            会发现实际只需要对App书点执行一个挂载操作就可以 了
          </p>
          <p>
            更新阶段和挂载阶段的主要区别：更新阶段的current树不为空，current树是已经存在的树，workInProgress树是正在render中的树
          </p>
          <p>
            <code>completeWork:</code>performUnitOfWork -&gt; completeUnitOfWork -&gt;
            completeWork。
            <br />
            completeWork负责将Fiber节点映射到DOM节点，其内部有三个关键动作：创建DOM节点，插入到DOM树（appendAllChildren函数完成），设置属性，最后赋值给workInProgress节点的stateNode属性
          </p>
          <p>
            <code>performUnitOfWork:</code>当遍历到叶子结点，就调用该函数。
          </p>
          <p>
            <code>completeUnitOfWork:</code>
            开启收集EffectList的大循环：
            <ol>
              <li>针对传入的当前节点，调用completeWork。</li>
              <li>
                将当前节点的副作用链插入到其父节点对应的副作用链（
                render阶段“工作成果”的一个集合）中，effectList记录的都是其需要更新的后代节点。
              </li>
              <li>
                以当前节点为起点，循环遍历其兄弟节点（return本次调用，触发兄弟节点对应的performUnitOfWork，开始执行beginWork，这样才能执行complateWork）及父节点（直接进入下一轮循环），
                这也就说明completeWork的执行是严格自底向上的。
              </li>
            </ol>
          </p>
        </Panel>
        <Panel header="3、render调用栈 -- commit" key="3">
          <p>
            <code>performSyncWorkOnRoot</code>
            为起点,这里的root指的是fiberRoot实例，整个commit是绝对同步的过程
          </p>
          <ul>
            <li>
              before mutaion:
              这个阶段DOM节点还没被渲染到界面上去，过程中会触发getSnapshotBeforeUpdate、useEffect（但是并不是立即执行，在此阶段，会把useEffect入列到react维护的调度队列中，给一个普通的优先级，异步执行，浏览器渲染完成后，react的调度队列，才开始执行useEffct产生的函数）
            </li>
            <li>mutaion: 这个阶段负责DOM的渲染，这个阶段会遍历effectList</li>
            <li>
              layout:
              这个阶段处理DOM渲染完毕后的收尾逻辑，会触发componentDidmount、componentDidUpdate、useLayoutEffect，它还会把
              fiberRoot的current指针指向workInProgress Fiber树
            </li>
          </ul>
        </Panel>
      </Collapse>
    </div>
  );
}
